02 - Podstawy OpenCV

Wprowadzenie do przetwarzania obrazów

Politechnika Poznańska, Instytut Robotyki i Inteligencji Maszynowej

Ćwiczenie laboratoryjne 2: Podstawowe operacje na obrazach i elementy sterujące

Powrót do spisu treści ćwiczeń laboratoryjnych

Obsługa zdarzeń interfejsu - trackbar

Duża część funkcji dostępnych w OpenCV wymaga ustawienia parametrów, a ich wartość jest zależna od typu obrazów, na których wykonywane są operacje. Sposobem na ułatwienie dobrania wartości parametru jest wykorzystanie elementu graficznego interfejsu użytkownika o nazwie trackbar. Pozwala on kontrolować wartość wybranej zmiennej w programie, a tym samym na podgląd w czasie rzeczywistym efektu działania algorytmu w zależności od parametru.

Więcej o trackbarach możesz sprawdzić w tutorialu: https://docs.opencv.org/5.x/da/d6a/tutorial_trackbar.html.

import cv2
import numpy as np


def empty_callback(value):
    pass

# create a black image, a window
img = np.zeros((300, 512, 3), dtype=np.uint8)
cv2.namedWindow('image')

# create trackbars for color change
cv2.createTrackbar('R', 'image', 0, 255, empty_callback)
cv2.createTrackbar('G', 'image', 0, 255, empty_callback)
cv2.createTrackbar('B', 'image', 0, 255, empty_callback)

# create switch for ON/OFF functionality
switch_trackbar_name = '0 : OFF \n1 : ON'
cv2.createTrackbar(switch_trackbar_name, 'image', 0, 1, empty_callback)

while True:
    cv2.imshow('image', img)

    # sleep for 10 ms waiting for user to press some key, return -1 on timeout
    key_code = cv2.waitKey(10)
    if key_code == 27:
        # escape key pressed
        break

    # get current positions of four trackbars
    r = cv2.getTrackbarPos('R', 'image')
    g = cv2.getTrackbarPos('G', 'image')
    b = cv2.getTrackbarPos('B', 'image')
    s = cv2.getTrackbarPos(switch_trackbar_name, 'image')

    if s == 0:
        # assign zeros to all pixels
        img[:] = 0
    else:
        # assign the same BGR color to all pixels
        img[:] = [b, g, r]

# closes all windows (usually optional as the script ends anyway)
cv2.destroyAllWindows()

UWAGA

W przykładzie do wszystkich trackbarów podłączono tę samą funkcję empty_callback, która nie wykonuje żadnej operacji. Należy pamiętać, że funkcja ta obsługuje wywołanie zdarzenia od każdego trackbaru, w związku z czym w większości przypadków powinna być inna dla każdego elementu. Argument value, który przyjmuje, to wartość trackbaru. Prosty sposób prezentacji działania to dodanie do niej linijki:

print(f'Trackbar reporting for duty with value: {value}')

💥 Zadanie do wykonania 💥

Uruchom przykładowy, dostępny powyżej program. Zmodyfikuj funkcję empty_callback w taki sposób, aby wyświetlała zmienną value w konsoli.

Operacje na pikselach - progowanie

W celu wykonania binaryzacji obrazu (zamiany do formatu, w którym występują tylko dwie wartości / kolory - biały / czarny) wykorzystuje się operację progowania. Zapoznać się z instrukcją: https://docs.opencv.org/5.x/d7/d4d/tutorial_py_thresholding.html.

UWAGA Trackbar należy podłączyć do okna, które istnieje w momencie tworzenia trackbaru. W celu utworzenia okna (bez podawania obrazu do wyświetlenia) skorzystać z funkcji cv2.namedWindow(‘windowName’).

Zadania do wykonania (w podanej kolejności!):

UWAGA Program z poniższych kroków powinien działać w czasie rzeczywistym, tj. zmiana jednego z suwaków powoduje zmianę wyświetlanego obrazu wynikowego i nie blokuje wyświetlania obrazu. Wykorzystaj do tego nieskończoną pętlę.

Zmiana rozmiaru - skalowanie obrazów

Obraz jest dwuwymiarową funkcją dyskretną. Po zastosowaniu powyższych przekształceń część pikseli jest przekształcana w niecałkowite współrzędne, a część pikseli nowego obrazu nie ma określonej wartości. Aby ją wyznaczyć konieczne jest zastosowanie interpolacji. Istnieje wiele metoda, z których omówione zostaną tylko najpopularniejsze.

Duże obrazy często są trudne do wyświetlenia i przeanalizowania wykonanych operacji, a dodatkowo czas ich przetwarzania jest długi (obraz o rozmiarze 12 megapixeli, np. 4000 x 3000, zapisany bez kompresji w formacie RGB to około 36 MB!). Zapoznać się z funkcją cv2.resize: https://docs.opencv.org/5.x/da/d54/group__imgproc__transform.html#ga47a974309e9102f5f08231edc7e7529d.

UWAGA

Zwrócić uwagę na wykluczające się argumenty funkcji dsize oraz fx,fy. W języku Python argumenty opcjonalne podaje się podając ich nazwy.

Wywołanie funkcji skalującej do konkretnej rozdzielczości (parametr dsize), powinno wyglądać następująco:
img_scaled = cv2.resize(img_to_scale, dsize=(500, 500))

Natomiast w przypadku argumentów fx oraz fy, które pozwalają skalować proporcjonalnie, parametr dsize, który jest wymagany podajemy jako wartość (0, 0) lub None:
Img_scaled = cv2.resize(img_to_scale, (0, 0), fx=0.5, fy=0.5)

💥 Zadanie do wykonania 💥

Obrazy jako macierze - operacje matematyczne

Wszystkie wczytane obrazy przechowywane są jako tablice, na których możliwe jest wykonywanie operacji matematycznych na zasadzie element-wise (tj. odpowiedni piksel z odpowiadającym mu innym). Zapoznaj się z: https://docs.opencv.org/5.x/d0/d86/tutorial_py_image_arithmetics.html.

💥 Zadanie do wykonania 💥

UWAGA Zwróć uwagę, że rozmiary obrazów muszą być takie same, aby można było je dodawać. W przypadku, gdy obrazy mają różne rozmiary, należy je skalować lub przyciąć.

Zadania do samodzielnej realizacji

💥 Zadanie do wykonania 💥

Wykonywanie wielu operacji na tak dużych macierzach jak obrazy może być czasochłonne. W celu wyznaczenia czasu trwania fragmentu programu można skorzystać z dedykowanych do tego funkcji. Zapoznać się z: https://docs.python.org/3/library/time.html#time.perf_counter oraz zbadaj, jak zmienia się czas skalowania obrazu w zależności od użytej interpolacji.

💥 Zadanie do wykonania 💥

Zapoznaj się z adaptacyjnym progowaniem (sekcja Adaptive thresholdng): https://docs.opencv.org/5.x/d7/d4d/tutorial_py_thresholding.html.

💥 Zadanie do wykonania 💥

Bazując na: https://docs.opencv.org/5.x/d0/d86/tutorial_py_image_arithmetics.html, napisz funkcję wyznaczającą negatyw obrazu.